import { ref, reactive, nextTick } from "vue";
import { BinarySearchTree } from "@/datastructure/BinarySearchTree.ts";
import { PriorityQueue } from "@/datastructure/PriorityQueue.ts";
import { IPriorityQueue } from "@/interface";
import { sleep, download, reader } from "@/utils";
import {
  IOperateGroup,
  IBinarySearchTreeKey,
  IBinarySearchTree,
  IBinarySearchTreeMethods,
  IBinarySearchTreeMethodsLiteral,
} from "@/interface";
import { baseConfig, initConfig } from "@/config";

/* 定义一些全局变量 */
const tree = ref<IBinarySearchTree>(new (BinarySearchTree as any)());
const pq = ref<IPriorityQueue>(new (PriorityQueue as any)());
const passNode = ref<string | number>(-1);
const inputs = ref<Array<any>>([]);
const fileInputs = ref<Array<any>>([]);
const root = reactive({
  el: null,
  other: null,
});
const controller = reactive({
  showMax: false,
  showMin: false,
  showPreOrderTraversal: false,
  showMidOrderTraversal: false,
  showPostOrderTraversal: false,
  showSearch: false,
});

const bstHint = reactive({
  max: "",
  min: "",
  preOrderTraversal: "",
  midOrderTraversal: "",
  postOrderTraversal: "",
  search: "",
});
const operateGroup = ref<Array<IOperateGroup>>([
  {
    name: "插入",
    value: "",
    event: "insert",
    rules: [
      { type: "number", message: "请输入数字", trigger: "change" },
      { type: "number", message: "请输入数字", trigger: "blur" },
    ],
    params: "val",
  },
  {
    name: "删除",
    value: "",
    event: "remove",
    rules: [
      { type: "number", message: "请输入数字", trigger: "change" },
      { type: "number", message: "请输入数字", trigger: "blur" },
    ],
    params: "val",
  },
  {
    name: "查找",
    value: "",
    event: "search",
    rules: [
      { type: "number", message: "请输入数字", trigger: "change" },
      { type: "number", message: "请输入数字", trigger: "blur" },
    ],
    params: "val",
  },
  {
    name: "最大值",
    event: "max",
    params: "Fn",
  },
  {
    name: "最小值",
    event: "min",
    params: "Fn",
  },
  {
    name: "先序遍历",
    event: "preOrderTraversal",
    params: "Fn",
  },
  {
    name: "中序遍历",
    event: "midOrderTraversal",
    params: "Fn",
  },
  {
    name: "后序遍历",
    event: "postOrderTraversal",
    params: "Fn",
  },
  {
    name: "清空",
    event: "clear",
    params: "Fn",
  },
  {
    name: "生成二叉树",
    event: "generateBST",
    params: "val",
    type: "file",
    rules: []
  },
  {
    name: "导出二叉树",
    event: "exportBST",
    params: "Fn"
  }
]);

const useBST = <T>(props: any, _this: any, args?: T & any) => {

  const { $message } = args;

  /* 重置控制器 */
  const resetController = () => {
    bstHint.max = "";
    bstHint.min = "";
    bstHint.preOrderTraversal = "";
    bstHint.midOrderTraversal = "";
    bstHint.postOrderTraversal = "";
    bstHint.search = "";
    passNode.value = -1;
    controller.showMax = false;
    controller.showMin = false;
    controller.showPreOrderTraversal = false;
    controller.showMidOrderTraversal = false;
    controller.showPostOrderTraversal = false;
    controller.showSearch = false;
    pq.value.clear();
  };

  // 取出队列中的每一项执行
  const cycleExecute = async (_pq: { value: IPriorityQueue } = pq, time: number = 400) => {
    try {
      while (!_pq.value.isEmpty()) {
        await sleep(time);
        const _delay = _pq.value.dequeue().element;
        _delay();
      }
    } catch (error) {
      $message('优先级队列内部方法出错!')
      console.log("优先级队列内部方法出错", error);
    }
  };

  // @ts-ignore
  const treeMethods: IBinarySearchTreeMethods = {
    insert: (value: IBinarySearchTreeKey) => {
      if (value) {
        // 1.寻找父节点
        //  1.1.没有父节点: 将当前的节点作为根节点, 并在插入后初始化offset
        //  1.2.存在父节点: 根据父节点的offset与isLeft属性判断当前节点的位置
        let isRoot = false;
        // @ts-ignore
        tree.value.insert(Number(value), (parent, key) => {
          const node = { offset: 0, isLeft: false, isRoot: true, top: 0, level: 0 };
          if (!parent) {
            isRoot = true;
          } else {
            node.isLeft = key === "left";
            node.offset =
              key === "left"
                ? parent.offset - initConfig.baseNodeGap
                : parent.offset + initConfig.baseNodeGap;
            node.isRoot = false;
            node.top = parent.top + baseConfig.levelInterval;
            node.level = parent?.level + 1;
          }
          return node;
        });
        resetController();
        if (isRoot) {
          // 插入后初始化offset
          nextTick(() => {
            // @ts-ignore
            const { left, top } = root.el.getBoundingClientRect();
            tree.value.root.offset = left;
            tree.value.root.top = top;
            tree.value.root.$el = root.el;
            tree.value.root.level = 0;
          });
        }
      }
    },
    remove: async (value: IBinarySearchTreeKey) => {
      if (value) {
        resetController();
        let index = 0;
        tree.value.remove(Number(value), (key: IBinarySearchTreeKey) => {
          const element = () => (passNode.value = Number(key));
          pq.value.enqueue(element, index++);
        });
        await cycleExecute();
      }
    },
    search: (key: IBinarySearchTreeKey) => {
      treeMethods.mostValue("search", "showSearch", [Number(key)]);
    },
    mostValue: async (method: string, control: string, args: any = []) => {
      resetController();
      let index = 0;
      let temp: any = null;
      args = [
        ...args,
        (key: IBinarySearchTreeKey) => {
          temp = key;
          const element = () => (passNode.value = Number(key));
          pq.value.enqueue(element, index++);
        },
      ];
      // @ts-ignore
      const value = tree.value[method](...args);
      await cycleExecute();
      // @ts-ignore
      bstHint[method] = value || temp;
      // @ts-ignore
      controller[control] = true;
    },
    max: () => {
      treeMethods.mostValue("max", "showMax");
    },
    min: () => {
      treeMethods.mostValue("min", "showMin");
    },
    orderTraversal: async (method: string, control: string) => {
      resetController();
      let index = 0;
      let value = "";
      // @ts-ignore
      tree.value[method]((key) => {
        if (value === "") {
          // @ts-ignore
          controller[control] = true;
        }
        const element = () => {
          // @ts-ignore
          passNode.value = Number(key);
          value += `${key} -> `;
          // @ts-ignore
          bstHint[method] = value;
        };
        pq.value.enqueue(element, index++);
      });
      await cycleExecute();
      // @ts-ignore
      bstHint[method] = value + "null";
    },
    preOrderTraversal: () => {
      treeMethods.orderTraversal("preOrderTraversal", "showPreOrderTraversal");
    },
    midOrderTraversal: () => {
      treeMethods.orderTraversal("midOrderTraversal", "showMidOrderTraversal");
    },
    postOrderTraversal: () => {
      treeMethods.orderTraversal("postOrderTraversal", "showPostOrderTraversal");
    },
    clear: () => {
      root.el = null;
      root.other = null;
      tree.value.clear();
    },
    // import file
    generateBST: () => {
      const files = fileInputs.value[0].files;
      if (files.length > 0) {
        reader(files[0], async (data: any) => {
          try {
            resetController();
            const json = JSON.parse(data);
            // @ts-ignore
            const genBSTPQ = ref<IPriorityQueue>(new PriorityQueue());
            json.data.forEach((key: IBinarySearchTreeKey, index: number) => {
              // 这里调insert的时候, insert内部会调resetController() 把数据清空
              const element = () => treeMethods.insert(key);
              genBSTPQ.value.enqueue(element, index++);
            })
            await cycleExecute(genBSTPQ, 250);
          } catch (error) {
            $message('导入数据有误, 请检查后重新导入！');
          }
        });
      } else {
        $message('请先选择文件！');
      }
    },
    exportBST: () => {
      // 1.调用先序遍历将数字记录下来
      if (tree.value.root) {
        const bstArray: Array<number> = [];
        tree.value.preOrderTraversal((key) => bstArray.push(key as number));
        download("tree.json", bstArray);
      } else {
        $message('当前没有数据！');
      }
    }
  };

  const handleClick = (group: IOperateGroup) => {
    const method: IBinarySearchTreeMethodsLiteral = group.event;
    // @ts-ignore
    treeMethods[method](group.value as any);
    group.value = "";
  };

  // 获取二叉搜索树根节点
  const handleReceiveRoot = (component: any) => {
    if (!root.el && component) {
      root.el = component.$el;
      root.other = component;
    }
  };

  // 接收输入框ref
  const receiveInput = (component: any, group: IOperateGroup) => {
    nextTick(() => {
      const inputElm = component.$refs.rawFile;
      inputElm && inputs.value.push(inputElm);
      if (group.type === "file" && inputElm) {
        fileInputs.value.push(inputElm);
      }
    })
  }

  return {
    resetController,
    cycleExecute,
    operateGroup,
    handleClick,
    treeMethods,
    handleReceiveRoot,
    receiveInput,
    tree,
    pq,
    passNode,
    inputs,
    fileInputs,
    root,
    controller,
    bstHint
  }
}

export default useBST;

export { useBST };
